package cn.com.cdb.ldms.modules.system.components;

import cn.com.cdb.ldms.base.page.annotation.FieldConfig;
import cn.com.cdb.ldms.base.page.annotation.Validation;
import cn.com.cdb.ldms.base.page.annotation.ViewConfig;
import cn.com.cdb.ldms.modules.system.domain.Dict;
import cn.com.cdb.ldms.modules.system.domain.DictDetail;
import cn.com.cdb.ldms.modules.system.mapper.DictDetailMapper;
import cn.com.cdb.ldms.modules.system.mapper.DictMapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.common.collect.Maps;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

@Component
@RequiredArgsConstructor
@Slf4j
public class ViewConfigGenerator {
    protected volatile static ConcurrentHashMap<String, LinkedHashMap<String, Object>> dictMap = new ConcurrentHashMap<>();
    private final DictMapper dictMapper;
    private final DictDetailMapper dictDetailMapper;

    @PostConstruct
    public void init() {
        loadDictData();
    }

    //每5秒执行一次
    @Scheduled(fixedDelay = 5000L)
    public void autoLoad() {
        log.info("定时刷新数据字典到内存");
        loadDictData();
    }

    /**
     * 加载数据字典
     */
    public void loadDictData() {
        // 1. 使用 ConcurrentHashMap 保证线程安全
        ConcurrentHashMap<String, LinkedHashMap<String, Object>> tempDictMap = new ConcurrentHashMap<>();

        // 2. 批量查询所有字典
        List<Dict> dictList = dictMapper.selectList(new LambdaQueryWrapper<>());

        // 3. 提取所有字典ID，用于批量查询明细
        List<Long> dictIds = dictList.stream()
                .map(Dict::getId)
                .collect(Collectors.toList());

        // 4. 批量查询所有字典明细（按 dictId 分组，避免多次查询）
        Map<Long, List<DictDetail>> detailsByDictId = dictDetailMapper.selectList(
                        new LambdaQueryWrapper<DictDetail>()
                                .in(DictDetail::getDictId, dictIds)
                                .orderByAsc(DictDetail::getDictSort)
                ).stream()
                .collect(Collectors.groupingBy(DictDetail::getDictId));

        // 5. 并行处理字典数据
        dictList.parallelStream().forEach(dict -> {
            List<DictDetail> dictDetails = detailsByDictId.getOrDefault(dict.getId(), Collections.emptyList());

            // 使用 computeIfAbsent 原子操作
            Map<String, Object> detailMap = tempDictMap.computeIfAbsent(
                    dict.getName(),
                    k -> new LinkedHashMap<>()
            );

            // 填充明细数据
            dictDetails.forEach(detail -> {
                detailMap.put(detail.getValue(), detail.getLabel());
            });
        });

        // 6. 原子替换（避免中间状态）
        dictMap = tempDictMap;
    }

    public List<Map> getFieldOptions(String fieldName) {
        final Map<String, Object> stringObjectMap = dictMap.get(fieldName);
        List<Map> rst = Lists.newArrayList();
        if (Objects.isNull(stringObjectMap)) {
            return rst;
        }
        stringObjectMap.forEach((value, label) -> {
            Map<String, Object> option = Maps.newHashMap();
            option.put("value", value);
            option.put("label", label);
            rst.add(option);
        });
        return rst;
    }

    public Map<String, Object> generateConfig(Class<?> entityClass) {
        Map<String, Object> config = new LinkedHashMap<>();
        ViewConfig viewConfig = entityClass.getAnnotation(ViewConfig.class);

        // 基础信息
        config.put("title", viewConfig != null ? viewConfig.title() : "");
        config.put("defaultPageSize", viewConfig != null ? viewConfig.defaultPageSize() : 10);

        // 获取所有字段配置
        List<Field> fields = Arrays.stream(entityClass.getDeclaredFields()).filter(f -> f.isAnnotationPresent(FieldConfig.class)).sorted(Comparator.comparingInt(f -> f.getAnnotation(FieldConfig.class).order())).collect(Collectors.toList());

        // 生成表格列配置
        config.put("tableColumns", generateTableColumns(fields));

        // 生成搜索表单配置
        config.put("searchConfig", generateSearchConfig(fields));

        // 生成编辑表单配置
        config.put("formConfig", generateFormConfig(fields));

        return config;
    }

    private List<Map<String, Object>> generateTableColumns(List<Field> fields) {
        return fields.stream().filter(field -> field.getAnnotation(FieldConfig.class).showInTable()).map(field -> {
            FieldConfig fc = field.getAnnotation(FieldConfig.class);
            Map<String, Object> column = new LinkedHashMap<>();
            column.put("prop", field.getName());
            column.put("label", fc.label());
            return column;
        }).collect(Collectors.toList());
    }

    private List<Map<String, Object>> generateSearchConfig(List<Field> fields) {
        return fields.stream().filter(field -> field.getAnnotation(FieldConfig.class).searchable()).map(field -> {
            FieldConfig fc = field.getAnnotation(FieldConfig.class);
            Map<String, Object> item = new LinkedHashMap<>();
            item.put("prop", field.getName());
            item.put("label", fc.label());

            // 确定字段类型
            String type = fc.searchType();
            if (type.isEmpty()) {
                type = inferFieldType(field.getType());
            }
            item.put("type", type.toLowerCase());

            // 设置placeholder
            if (!fc.searchPlaceholder().isEmpty()) {
                item.put("placeholder", fc.searchPlaceholder());
            }

            // 日期类型特殊处理
            if (type.equalsIgnoreCase("date")) {
                item.put("dateType", fc.searchDateType().name().toLowerCase());
            }

            // 处理选项
            if (type.equalsIgnoreCase("select") && fc.options().length > 0) {
//                item.put("options", Arrays.stream(fc.options()).map(opt -> Map.of("label", opt.label(), "value", opt.value())).collect(Collectors.toList()));
                item.put("options", getFieldOptions(field.getName()));
            }

            // 添加验证规则
            if (fc.searchValidations().length > 0) {
                item.put("rules", convertValidations(fc.searchValidations()));
            }

            return item;
        }).collect(Collectors.toList());
    }

    private List<Map<String, Object>> generateFormConfig(List<Field> fields) {
        return fields.stream().filter(field -> field.getAnnotation(FieldConfig.class).editable()).map(field -> {
            FieldConfig fc = field.getAnnotation(FieldConfig.class);
            Map<String, Object> item = new LinkedHashMap<>();
            item.put("prop", field.getName());
            item.put("label", fc.label());

            // 确定字段类型
            String type = fc.formType();
            if (type.isEmpty()) {
                type = inferFieldType(field.getType());
            }
            item.put("type", type.toLowerCase());

            // 设置placeholder
            if (!fc.formPlaceholder().isEmpty()) {
                item.put("placeholder", fc.formPlaceholder());
            }

            // 设置禁用状态
            if (fc.alwaysDisabled()) {
                item.put("disabled", true);
            } else {
                Map<String, Boolean> disabled = new HashMap<>();
                disabled.put("onAdd", fc.disabledOnAdd());
                disabled.put("onEdit", fc.disabledOnEdit());
                item.put("disabled", disabled);
            }

            // 处理选项
            if (type.equalsIgnoreCase("select") && fc.options().length > 0) {
                item.put("options", Arrays.stream(fc.options()).map(opt -> Map.of("label", opt.label(), "value", opt.value())).collect(Collectors.toList()));
            }

            // 添加验证规则
            if (fc.formValidations().length > 0) {
                item.put("rules", convertValidations(fc.formValidations()));
            }

            return item;
        }).collect(Collectors.toList());
    }

    private String inferFieldType(Class<?> fieldType) {
        if (String.class.equals(fieldType)) {
            return "input";
        } else if (Number.class.isAssignableFrom(fieldType)) {
            return "number";
        } else if (Boolean.class.equals(fieldType) || boolean.class.equals(fieldType)) {
            return "switch";
        } else if (Date.class.isAssignableFrom(fieldType) || LocalDate.class.equals(fieldType) || LocalDateTime.class.equals(fieldType)) {
            return "date";
        } else if (Enum.class.isAssignableFrom(fieldType)) {
            return "select";
        }
        return "input";
    }

    private List<Map<String, Object>> convertValidations(Validation[] validations) {
        return Arrays.stream(validations).map(v -> {
            Map<String, Object> rule = new LinkedHashMap<>();
            rule.put("type", v.type().toLowerCase());
            rule.put("message", v.message());

            switch (v.type().toLowerCase()) {
                case "regex":
                    rule.put("pattern", v.regex());
                    break;
                case "min":
                    rule.put("min", v.min());
                    break;
                case "max":
                    rule.put("max", v.max());
                    break;
            }

            return rule;
        }).collect(Collectors.toList());
    }
}